package at.horario.service.impl;

import at.horario.dao.*;
import at.horario.model.*;
import at.horario.service.HorarioManager;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HorarioManagerImpl extends GenericManagerImpl<Horario, Long> implements HorarioManager {
    private GenericDao<HorarioClasseGrupo, Long> horarioClasseGrupoDao;
    private GenericDao<Classe, Integer> classeDao;
    private GenericDao<Professor, Integer> professorDao;
    private GenericDao<Grupo, String> grupoDao;
    private GenericDao<Turma, Long> turmaDao;
    private ChDisciplinaDao chDisciplinaDao;
    private ChProfessorDao chProfessorDao;
    private ProfessorTurmaDao professorTurmaDao;
    private GenericDao<Ciclo, Integer> cicloDao;


    public void setCicloDao(GenericDao<Ciclo, Integer> cicloDao) {
        this.cicloDao = cicloDao;
    }

    public void setHorarioClasseGrupoDao(GenericDao<HorarioClasseGrupo, Long> horarioClasseGrupoDao) {
        this.horarioClasseGrupoDao = horarioClasseGrupoDao;
    }

    public void setClasseDao(GenericDao<Classe, Integer> classeDao) {
        this.classeDao = classeDao;
    }

    public GenericDao<Professor, Integer> getProfessorDao() {
        return professorDao;
    }

    public void setProfessorDao(GenericDao<Professor, Integer> professorDao) {
        this.professorDao = professorDao;
    }

    public GenericDao<Turma, Long> getTurmaDao() {
        return turmaDao;
    }

    public void setTurmaDao(GenericDao<Turma, Long> turmaDao) {
        this.turmaDao = turmaDao;
    }

    public ChDisciplinaDao getChDisciplinaDao() {
        return chDisciplinaDao;
    }

    public void setChDisciplinaDao(ChDisciplinaDao chDisciplinaDao) {
        this.chDisciplinaDao = chDisciplinaDao;
    }

    public ChProfessorDao getChProfessorDao() {
        return chProfessorDao;
    }

    public void setChProfessorDao(ChProfessorDao chProfessorDao) {
        this.chProfessorDao = chProfessorDao;
    }

    public ProfessorTurmaDao getProfessorTurmaDao() {
        return professorTurmaDao;
    }

    public void setProfessorTurmaDao(ProfessorTurmaDao professorTurmaDao) {
        this.professorTurmaDao = professorTurmaDao;
    }

    public void setGrupoDao(GenericDao<Grupo, String> grupoDao) {
        this.grupoDao = grupoDao;
    }

    public HorarioManagerImpl(final HorarioDao horarioDao) {
        super(horarioDao);
        //this.horarioDao = horarioDao;
    }

    public Horario save(Horario horario, Map<String, Object> classeGrupo) {
        horario.setDataCriacao(new Date());
        super.genericDao.save(horario);
        System.out.println(horario);
        Pattern p = Pattern.compile("classe(\\d+)(.*?)");

        //salvar os grupos
        List<HorarioClasseGrupo> hcgs = new ArrayList<HorarioClasseGrupo>(classeGrupo.size());
        List<Professor> professores = new ArrayList<Professor>();

        //guarda o ultimo professor da disciplina
        HashMap<Disciplina, Professor> professorDisciplina = new LinkedHashMap<Disciplina, Professor>();


        int numTurmas = 0;
        int numProfessores = 0;

        List<Turma> turmas = new ArrayList<Turma>();
        List<ProfessorTurma> professorTurmas = new ArrayList<ProfessorTurma>();


        Professor professor;
        ProfessorTurma professorTurma;
        //TODO: Lazy Initialization
        Set<Classe> classes = cicloDao.get(horario.getCiclo().getId()).getClasses();
        Map<Classe, Integer> numClasses = new HashMap<Classe, Integer>();
        for (Classe classe : classes) {
            numClasses.put(classe, 1);
        }

        for (String key : classeGrupo.keySet()) {
            Matcher m = p.matcher(key);
            m.matches();

            Classe classe = classeDao.get(Integer.valueOf(m.group(1)));
            Grupo grupo = grupoDao.get(m.group(2));
            HorarioClasseGrupo hcg = new HorarioClasseGrupo(horario, classe, grupo, Integer.parseInt(classeGrupo.get(key).toString()));
            hcgs.add(hcg);
        }
        Collections.sort(hcgs, new Comparator<HorarioClasseGrupo>() {
            public int compare(HorarioClasseGrupo o1, HorarioClasseGrupo o2) {
                return (o1.getClasse().getClasseId() - o2.getClasse().getClasseId()) * 100 + (o1.getGrupo().getOrdem() - o2.getGrupo().getOrdem());
            }
        });

        for (int k = 0; k < hcgs.size(); k++) {
            HorarioClasseGrupo hcg = hcgs.get(k);
            int numClasse = numClasses.get(hcg.getClasse());

            for (int i = 0; i < hcg.getNumTurmas(); ++i) {
                Turma turma = new Turma(++numTurmas, numClasse++, horario, hcg.getClasse(), hcg.getGrupo(), 0);
                //turmaDao.save(turma);

                turmas.add(turma);
                for (Disciplina disciplina : hcg.getGrupo().getDisciplinas()) {
                    professor = professorDisciplina.get(disciplina);//ultimo professor da disciplina
                    ChDisciplina cd = chDisciplinaDao.find(disciplina, horario.getTurno(), hcg.getGrupo());
                    Integer chDisciplinaTurnoGrupo = cd.getCargaHoraria();
                    if (professor == null || professor.getCh() + chDisciplinaTurnoGrupo > professor.getChMax()) {
                        //professor?.save()
                        // se o professor existir o professor da disciplina vamos criar um novo
                        //criar um novo professor
                        int numDisciplina = professor == null ? 1 : professor.getNumDisciplina() + 1;
                        professor = new Professor(++numProfessores, numDisciplina, randomAlphabetic(10), disciplina, chProfessorDao.find(disciplina, horario.getCiclo()).getCargaHoraria(), horario);
                        professor.setProfessorOcupacaos(new HashSet<ProfessorOcupacao>());
                        professor.getProfessorOcupacaos().add(new ProfessorOcupacao(professor, 21));
                        //professorDao.save(professor);
                        //professores << professor
                        professores.add(professor);
                        professorDisciplina.put(disciplina, professor);
                    }

                    //professorTurmaDao.save(professor, turma, chDisciplinaTurnoGrupo);
                    professorTurma = new ProfessorTurma(professor, turma, chDisciplinaTurnoGrupo);
                    professorTurmas.add(professorTurma);

                    //ProfessorTurma.link(professor, turma, chDisciplinaTurnoGrupo)
                    professor.addCh(chDisciplinaTurnoGrupo);

                }
            }
            numClasses.put(hcg.getClasse(), numClasse);

        }

        horarioClasseGrupoDao.saveOrUpdateAll(hcgs);
        turmaDao.saveOrUpdateAll(turmas);
        professorDao.saveOrUpdateAll(professores);
        professorTurmaDao.saveOrUpdateAll(professorTurmas);


        return horario;


    }


    public static void main(String[] args) {
        String[] valores = {"classe10Global", "classe10Ciencias", "classe9Global", "classe10Letras", "classe8Global"};
        Pattern p = Pattern.compile("classe(\\d+)(.*?)");

        for (int i = 0; i < valores.length; i++) {
            String valore = valores[i];
            Matcher m = p.matcher(valore);

            m.matches();
            System.out.println("+++" + m.group(1));
            System.out.println("+++" + m.group(2));
            //}
        }


    }
}